import { MyFileDir } from "../model/models/MyFileDirTable";
import { ImgExt, VideoExt, staticPath, staticPathName } from "../utils/const";
import { sharpImg } from "../utils/operateImgFile";
import { getScreenshot } from "../utils/operateVideoFile";
import { fileLog, sqlLog } from "../log/index";
import fs from "fs";
import path from "path";
import { MyFileDirItf } from "../interface/interface";
import { deleteByName } from "../service/MyFileDirTable_Serivce";
import { MediaPromise } from "../interface/interface"
import Ffmpeg from "fluent-ffmpeg";

// (function (){
//     let obj: MyFileDirItf = {
//         parentId: 0,
//         folderOrFileId: 0,
//         path: ""
//     }
//     //  MyFileDir
// })()

const staticBasicPath = path.resolve(staticPath);

 function replaceStaticBasicPath(path: string) {
    return path.replace(staticBasicPath, "");
}

/**
 * @description: 处理文件资源
 * @param {string} mediaPath 资源路径
 * @param {number} parentId 父级的id
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function operateFile(mediaPath: string, parentId: number) {
    let stat = await fs.promises.stat(mediaPath);
    let relativePath = replaceStaticBasicPath(mediaPath);
    console.log(relativePath);
    let isExit = await pathExistInMysql(relativePath);
    if (isExit) {
        console.log(relativePath, "已经存在了");
        return;
    }
    let maxIndex = (await getPathMaxIndex(relativePath)) + 1;
    if (stat.isFile()) {
        // 文件
        let ext = path.extname(mediaPath).toLowerCase();
        let fireObj: MyFileDirItf = {
            parentId: parentId,
            folderOrFileId: maxIndex,
            path: relativePath,
            isFile: true,
            isImg: ImgExt.includes(ext),
            isVideo: VideoExt.includes(ext),
            size: stat.size,
            ext,
            thumbnailPath: "",
            duration: 0
        };

        try {
            // 然后对文件进行处理
            let obj = await operateImgAndVideoFile(mediaPath, fireObj.isImg, fireObj.isVideo, fireObj.size, fireObj.ext);
            fireObj.thumbnailPath = obj.path
            fireObj.duration = obj.duration
        } catch (error) {
            fileLog.error( error )
            console.log(mediaPath,'文件处理出问题了');
        }

        try {
            let rs = await MyFileDir.create({ ...fireObj });
        } catch (error) {
            console.log(error);
            sqlLog.error(`${mediaPath}, "存入失败"`);
        }
    } else if (stat.isDirectory()) {
        // console.log(path.resolve( relativePath ));
        // 文件夹
        // 1.先把文件夹存入数据库
        let dirObj: MyFileDirItf = {
            parentId: parentId,
            folderOrFileId: maxIndex,
            path: relativePath,
            isFile: false,
            isImg: false,
            isVideo: false,
            size: 0,
            ext: "",
            thumbnailPath: "",
            duration: 0
        };
        try {
            // 存入数据库
            let rs = await MyFileDir.create({ ...dirObj });
            // 2.然后再管下面的文件
            let dir = await getDir(mediaPath);
            dir = dir.filter((item) => !item.startsWith("operateFileByWeb"));
            for (let i of dir) {
                let p = path.resolve(mediaPath, i);
                // console.log(p);
                // 递归
                await operateFile(p, rs.dataValues.id);
            }
        } catch (error) {
            console.log(error);
            sqlLog.error(`${mediaPath}, "存入失败"`);
        }
    }
}

// operateFile(staticBasicPath, 0);

/**
 * @description: 获得文件夹中的内容并去掉点开头的文件
 * @param {string} path 资源路径
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function getDir(path: string): Promise<string[]> {
    let dir = await fs.readdirSync(path);
    // 去除文件夹中以.开头的文件
    return dir.filter((item) => !item.startsWith("."));
}

/**
 * @description: 如果给定了path,会寻找路径下面的文件标号最大值，否则会找根路径，根路径是指0
 * @param {string} path 去掉了staticBasicPath后的路径
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function getPathMaxIndex(path?: string, parentId: number = 0) {
    let arr = await MyFileDir.findAll({
        where: path
            ? {
                  path,
              }
            : {
                  parentId,
              },
    });
    let max = 0;
    for (const item of arr) {
        max = max < item.dataValues.folderOrFileId ? item.dataValues.folderOrFileId : max;
    }
    return max;
}

/**
 * @description: 路径已经存在mysql中了
 * @param {string} path
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function pathExistInMysql(path: string) {
    let data = await MyFileDir.findAll({
        where: {
            path,
        },
    });
    return data.length > 0;
}

// 压缩图存放路径
const snapPath = path.resolve(__dirname, "../../static/");

/**
 * @description: 处理图片和视频资源
 * @param {string} mediaPath
 * @param {boolean} isImg
 * @param {boolean} isVideo
 * @param {number} size
 * @param {string} ext
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
async function operateImgAndVideoFile(mediaPath: string, isImg: boolean, isVideo: boolean, size: number, ext: string): Promise<MediaPromise> {
    
    let name = path.basename(mediaPath, ext);
    if (isImg) {
        if (size < 1 * 1024 * 1024) {
            // 小于1m的不需要预览图
            return {
                path: "",
                duration: 0
            };
        }
        try {
            let thumbnailPath = await sharpImg(mediaPath, name, ext);
            return {
                path: thumbnailPath.path.replace(snapPath, ""),
                duration: thumbnailPath.duration
            };
        } catch (error) {
            fileLog.error(`${mediaPath} 缩略图处理失败`);
        }
    } else if (isVideo) {
        try {
            let thumbnailPath = await getScreenshot(mediaPath, ext);
            console.log(thumbnailPath);
            return {
                path: thumbnailPath.path.replace(snapPath, ""),
                duration: thumbnailPath.duration
            };
        } catch (error) {
            fileLog.error(`${mediaPath} 缩略图处理失败`);
        }
    }
    return {
        path: "",
        duration: 0
    };
}

/**
 * @description: 检查后缀是否和文件匹配
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function checkExt() {
    let res = await MyFileDir.findAll();
    for (const item of res) {
        let data = item.dataValues as MyFileDirItf;
        // 匹配路径是否和后缀匹配
        if (path.extname(data.path) !== data.ext && data.isFile) {
            data.ext = path.extname(data.path);
            await MyFileDir.update(data, {
                where: {
                    id: data.id,
                },
            });
        }

        // 匹配文件夹的后缀是否为空
        if (!data.isFile && data.ext) {
            data.ext = "";
            await MyFileDir.update(data, {
                where: {
                    id: data.id,
                },
            });
        }

        // 判断文件是否和后缀匹配
        if (VideoExt.includes(data.ext.toLowerCase()) && data.isVideo) {
            continue;
        } else if (ImgExt.includes(data.ext.toLowerCase()) && data.isImg) {
            continue;
        } else if (!data.isFile && data.ext == "") {
            continue;
        } else {
            // 判断出错的
            console.log(
                data.path +
                    "判断错了,后缀为" +
                    `${data.ext}记录成了${data.isImg ? "图片" : ""}${data.isVideo ? "视频" : ""}${data.isFile ? "文件" : ""}`
            );
            if (VideoExt.includes(data.ext.toLowerCase())) {
                data.isVideo = true;
                data.isImg = false;
                data.isFile = true;
            } else if (ImgExt.includes(data.ext.toLowerCase())) {
                data.isVideo = false;
                data.isImg = true;
                data.isFile = true;
            }
            let res = await MyFileDir.update( data, {
                where: {
                    id: data.id
                }
            } )
        }
    }
}

/**
 * @description: 通过路径删除文件
 * @param {string} path
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function deleteFile(path: string) {
    try {
        let res = await fs.promises.unlink(path);
        console.log(path, "删除成功");
    } catch (error) {
        console.log(path, "删除失败");
    }
}

/**
 * @description: 处理修复截图失败的文件
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function HandlingErrorImages() {
    let res = await MyFileDir.findAll();
    let count = 0;
    for (let item of res) {
        let data = item.dataValues as MyFileDirItf;
        if (data.thumbnailPath) {
            let p = path.join(path.resolve(__dirname, "../../static"), data.thumbnailPath);
            let originPath = path.join(staticPath, data.path);
            try {
                let state = await fs.promises.stat(p);
            } catch (error) {
                console.log(originPath);
                let p = await operateImgAndVideoFile(originPath, data.isImg, data.isVideo, data.size, data.ext);
                data.thumbnailPath = p.path;
                let res = await MyFileDir.update(data, {
                    where: {
                        id: data.id,
                    },
                });
                count += res as unknown as number;
            }
        }
    }
}


// 修复所有视频的截图
export async function HandlingErrorVideoScreensnap() {
    let videos = await MyFileDir.findAll({
        where: {
            isVideo: true
        }
    })
    let count = 0
    for (const video of videos) {
        let data = video.dataValues as MyFileDirItf
        if( !data.thumbnailPath || data.thumbnailPath.trim() == '' ){
            let originPath = path.join(staticPath, data.path);
            let p = await operateImgAndVideoFile( originPath, data.isImg, data.isVideo, data.size, data.ext )
            data.thumbnailPath = p.path
            await MyFileDir.update( data, {
                where: {
                    id: data.id
                }
            } )
            count ++
        }
    }
    console.log(count);
}

/**
 * @description: 修改时间间隔
 * @return {*}
 * @author: tao wenbo 2419421809@qq.com
 */
export async function changeDuration() {
    let res = await MyFileDir.findAll({
        where: {
            isVideo: true,
            duration: 0
        }
    })
    for( let i of res ){
        let data = i.dataValues as MyFileDirItf
        let p = path.join( staticPath, i.dataValues.path )
        let duration = await getDuration( p )
        data.duration = duration
        await MyFileDir.update( data, {
            where: {
                id: data.id
            }
        } )
        console.log(p, duration);
    }
}


export async function getDuration(madiaPath: string): Promise<number>{
    return new Promise( (resolve) => {
        Ffmpeg.ffprobe(madiaPath, function (err: any, metadata: any) {
            if (err) {
                console.log(err);
            } else {
                // 
                // 获取宽高比
                let arr = metadata.streams;
                let duration = 0
                for (let i of arr) {
                    if (i.duration) {
                        console.log(i);
                        duration = Math.floor(i.duration * 1000) || 0
                        break;
                    }
                }
                resolve( duration )
            }
        });
    } )
}



